/////////////////////////////////////////////////////////////////////////////
// Name:        tts_custompronunciationdialog.cpp
// Purpose:     
// Author:      Julian Smart
// Modified by: 
// Created:     11/02/2009 20:01:56
// RCS-ID:      
// Copyright:   (c) Anthemion Software Limited
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/wx.h"
#include "wx/utils.h"
#include "wx/log.h"
#include "wx/tokenzr.h"

#if defined(__WXMSW__) && wxUSE_UXTHEME
#include "wx/msw/uxtheme.h"
#endif

#include "tts/tts_custompronunciationdialog.h"

/// Get an appropriate control border style
static wxBorder wxGetControlBorderStyle()
{
#if wxCHECK_VERSION(2,9,0)
    return wxBORDER_THEME;
#else
#ifdef __WXMSW__
#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
    return wxBORDER_SIMPLE;
#elif wxUSE_UXTHEME
    if (wxUxThemeEngine::GetIfActive())
        return wxBORDER_THEME;
#endif
    return wxBORDER_SUNKEN;
#else
    return wxBORDER_SUNKEN;
#endif
#endif
}

/*
 * wxTTSCustomPronunciationDialog type definition
 */

IMPLEMENT_DYNAMIC_CLASS( wxTTSCustomPronunciationDialog, wxDialog )


/*
 * wxTTSCustomPronunciationDialog event table definition
 */

BEGIN_EVENT_TABLE( wxTTSCustomPronunciationDialog, wxDialog )

////@begin wxTTSCustomPronunciationDialog event table entries
    EVT_LISTBOX( ID_CUSTOM_WORD_LISTBOX, wxTTSCustomPronunciationDialog::OnCustomWordListboxSelected )

    EVT_BUTTON( ID_ADD_CUSTOM_WORD, wxTTSCustomPronunciationDialog::OnAddCustomWordClick )

    EVT_BUTTON( ID_REMOVE_CUSTOM_WORD, wxTTSCustomPronunciationDialog::OnRemoveCustomWordClick )
    EVT_UPDATE_UI( ID_REMOVE_CUSTOM_WORD, wxTTSCustomPronunciationDialog::OnRemoveCustomWordUpdate )

    EVT_UPDATE_UI( ID_CUSTOM_WORD, wxTTSCustomPronunciationDialog::OnCustomWordUpdate )

    EVT_BUTTON( ID_CUSTOM_WORD_SAY, wxTTSCustomPronunciationDialog::OnCustomWordSayClick )
    EVT_UPDATE_UI( ID_CUSTOM_WORD_SAY, wxTTSCustomPronunciationDialog::OnCustomWordSayUpdate )

    EVT_TEXT( ID_CUSTOM_REPLACEMENT, wxTTSCustomPronunciationDialog::OnCustomReplacementTextUpdated )
    EVT_UPDATE_UI( ID_CUSTOM_REPLACEMENT, wxTTSCustomPronunciationDialog::OnCustomReplacementUpdate )

    EVT_BUTTON( ID_CUSTOM_REPLACEMENT_SAY, wxTTSCustomPronunciationDialog::OnCustomReplacementSayClick )
    EVT_UPDATE_UI( ID_CUSTOM_REPLACEMENT_SAY, wxTTSCustomPronunciationDialog::OnCustomReplacementSayUpdate )

////@end wxTTSCustomPronunciationDialog event table entries

END_EVENT_TABLE()

bool wxTTSCustomPronunciationDialog::m_showToolTips = true;

/*
 * wxTTSCustomPronunciationDialog constructors
 */

wxTTSCustomPronunciationDialog::wxTTSCustomPronunciationDialog()
{
    Init();
}

wxTTSCustomPronunciationDialog::wxTTSCustomPronunciationDialog( wxTTSTransformer* transformer, wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    Init();
    Create(transformer, parent, id, caption, pos, size, style);
}


/*
 * ebCustomPronunciationDialog creator
 */

bool wxTTSCustomPronunciationDialog::Create( wxTTSTransformer* transformer, wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    m_transformer = transformer;

////@begin wxTTSCustomPronunciationDialog creation
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
    wxDialog::Create( parent, id, caption, pos, size, style );

    CreateControls();
    if (GetSizer())
    {
        GetSizer()->SetSizeHints(this);
    }
    Centre();
////@end wxTTSCustomPronunciationDialog creation
    return true;
}


/*
 * wxTTSCustomPronunciationDialog destructor
 */

wxTTSCustomPronunciationDialog::~wxTTSCustomPronunciationDialog()
{
////@begin wxTTSCustomPronunciationDialog destruction
////@end wxTTSCustomPronunciationDialog destruction
}


/*
 * Member initialisation
 */

void wxTTSCustomPronunciationDialog::Init()
{
    m_ignoreEvents = false;
    m_transformer = NULL;
    m_speech = NULL;

////@begin wxTTSCustomPronunciationDialog member initialisation
    m_innerSizer = NULL;
    m_wordListCtrl = NULL;
    m_customWordCtrl = NULL;
    m_replacementWordCtrl = NULL;
    m_htmlWindow = NULL;
////@end wxTTSCustomPronunciationDialog member initialisation
}


/*
 * Control creation for ebCustomPronunciationDialog
 */

void wxTTSCustomPronunciationDialog::CreateControls()
{    
#ifdef __WXMAC__
    SetWindowVariant(wxWINDOW_VARIANT_SMALL);
#endif

////@begin wxTTSCustomPronunciationDialog content construction
    wxTTSCustomPronunciationDialog* itemDialog1 = this;

    wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
    itemDialog1->SetSizer(itemBoxSizer2);

    m_innerSizer = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer2->Add(m_innerSizer, 1, wxGROW|wxALL, 5);

    wxStaticText* itemStaticText4 = new wxStaticText( itemDialog1, wxID_STATIC, _("&Words:"), wxDefaultPosition, wxDefaultSize, 0 );
    m_innerSizer->Add(itemStaticText4, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP, 5);

    wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
    m_innerSizer->Add(itemBoxSizer5, 0, wxGROW, 5);

    wxArrayString m_wordListCtrlStrings;
    m_wordListCtrl = new wxListBox( itemDialog1, ID_CUSTOM_WORD_LISTBOX, wxDefaultPosition, wxSize(-1, 120), m_wordListCtrlStrings, wxLB_SINGLE );
    m_wordListCtrl->SetHelpText(_("The replacement words."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        m_wordListCtrl->SetToolTip(_("The replacement words."));
    itemBoxSizer5->Add(m_wordListCtrl, 1, wxGROW|wxALL, 5);

    wxBoxSizer* itemBoxSizer7 = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer5->Add(itemBoxSizer7, 0, wxGROW, 5);

    wxButton* itemButton8 = new wxButton( itemDialog1, ID_ADD_CUSTOM_WORD, _("&Add"), wxDefaultPosition, wxDefaultSize, 0 );
    itemButton8->SetHelpText(_("Click to add a new word."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        itemButton8->SetToolTip(_("Click to add a new word."));
    itemBoxSizer7->Add(itemButton8, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    wxButton* itemButton9 = new wxButton( itemDialog1, ID_REMOVE_CUSTOM_WORD, _("&Remove"), wxDefaultPosition, wxDefaultSize, 0 );
    itemButton9->SetHelpText(_("Click to remove the current word."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        itemButton9->SetToolTip(_("Click to remove the current word."));
    itemBoxSizer7->Add(itemButton9, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxBoxSizer* itemBoxSizer10 = new wxBoxSizer(wxHORIZONTAL);
    m_innerSizer->Add(itemBoxSizer10, 0, wxGROW, 5);

    wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer10->Add(itemBoxSizer11, 1, wxALIGN_CENTER_VERTICAL, 5);

    wxStaticText* itemStaticText12 = new wxStaticText( itemDialog1, wxID_STATIC, _("W&ord:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer11->Add(itemStaticText12, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP, 5);

    wxBoxSizer* itemBoxSizer13 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer11->Add(itemBoxSizer13, 0, wxGROW, 5);

    m_customWordCtrl = new wxTextCtrl( itemDialog1, ID_CUSTOM_WORD, _T(""), wxDefaultPosition, wxSize(200, -1), wxTE_READONLY );
    m_customWordCtrl->SetHelpText(_("The word to replace (not editable)."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        m_customWordCtrl->SetToolTip(_("The word to replace (not editable)."));
    itemBoxSizer13->Add(m_customWordCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxButton* itemButton15 = new wxButton( itemDialog1, ID_CUSTOM_WORD_SAY, _(">"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
    itemButton15->SetHelpText(_("Say the word."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        itemButton15->SetToolTip(_("Say the word."));
    itemBoxSizer13->Add(itemButton15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxTOP|wxBOTTOM, 5);

    wxBoxSizer* itemBoxSizer16 = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer10->Add(itemBoxSizer16, 1, wxALIGN_CENTER_VERTICAL, 5);

    wxStaticText* itemStaticText17 = new wxStaticText( itemDialog1, wxID_STATIC, _("R&eplacement:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer16->Add(itemStaticText17, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP, 5);

    wxBoxSizer* itemBoxSizer18 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer16->Add(itemBoxSizer18, 0, wxGROW, 5);

    m_replacementWordCtrl = new wxTextCtrl( itemDialog1, ID_CUSTOM_REPLACEMENT, _T(""), wxDefaultPosition, wxSize(200, -1), 0 );
    m_replacementWordCtrl->SetHelpText(_("Type the replacement word or sequence of phonemes here."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        m_replacementWordCtrl->SetToolTip(_("Type the replacement word or sequence of phonemes here."));
    itemBoxSizer18->Add(m_replacementWordCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxButton* itemButton20 = new wxButton( itemDialog1, ID_CUSTOM_REPLACEMENT_SAY, _(">"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
    itemButton20->SetHelpText(_("Say the replacement word."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        itemButton20->SetToolTip(_("Say the replacement word."));
    itemBoxSizer18->Add(itemButton20, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxTOP|wxBOTTOM, 5);

    m_htmlWindow = new wxTTSHtmlWindow( itemDialog1, ID_CUSTOM_PRONUNCIATION_HTMLWINDOW, wxDefaultPosition, wxSize(200, 150), wxHW_SCROLLBAR_AUTO|wxHSCROLL|wxVSCROLL|wxGetControlBorderStyle() );
    m_innerSizer->Add(m_htmlWindow, 1, wxGROW|wxALL, 5);

    wxStdDialogButtonSizer* itemStdDialogButtonSizer22 = new wxStdDialogButtonSizer;

    m_innerSizer->Add(itemStdDialogButtonSizer22, 0, wxGROW|wxALL, 5);
    wxButton* itemButton23 = new wxButton( itemDialog1, wxID_OK, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 );
    itemButton23->SetDefault();
    itemButton23->SetHelpText(_("Click to close the dialog."));
    if (wxTTSCustomPronunciationDialog::ShowToolTips())
        itemButton23->SetToolTip(_("Click to close the dialog."));
    itemStdDialogButtonSizer22->AddButton(itemButton23);

    itemStdDialogButtonSizer22->Realize();

////@end wxTTSCustomPronunciationDialog content construction

    if (m_transformer->GetUsageDescription().IsEmpty())
    {
        m_innerSizer->Show(m_htmlWindow, false);
    }
    else
        m_htmlWindow->SetPage(m_transformer->GetUsageDescription());

    FillWordList();
}


/*
 * Should we show tooltips?
 */

bool wxTTSCustomPronunciationDialog::ShowToolTips()
{
    return GetShowToolTips();
}

/*
 * Get bitmap resources
 */

wxBitmap wxTTSCustomPronunciationDialog::GetBitmapResource( const wxString& name )
{
    // Bitmap retrieval
////@begin wxTTSCustomPronunciationDialog bitmap retrieval
    wxUnusedVar(name);
    return wxNullBitmap;
////@end wxTTSCustomPronunciationDialog bitmap retrieval
}

/*
 * Get icon resources
 */

wxIcon wxTTSCustomPronunciationDialog::GetIconResource( const wxString& name )
{
    // Icon retrieval
////@begin wxTTSCustomPronunciationDialog icon retrieval
    wxUnusedVar(name);
    return wxNullIcon;
////@end wxTTSCustomPronunciationDialog icon retrieval
}

/// List words
void wxTTSCustomPronunciationDialog::FillWordList()
{
    if (!m_transformer)
        return;
        
    m_ignoreEvents = true;
    m_wordListCtrl->Clear();

    size_t i;
    for (i = 0; i < m_transformer->GetStrings().GetCount(); i++)
    {
        m_wordListCtrl->Append(m_transformer->GetStrings()[i]);
    }

    if (m_wordListCtrl->GetCount() > 0)
    {
        m_wordListCtrl->SetSelection(0);
        ShowWord(0);
    }

    m_ignoreEvents = false;
}

/// Show given word
void wxTTSCustomPronunciationDialog::ShowWord(int i)
{
    m_ignoreEvents = true;

    if (i == -1)
    {
        m_customWordCtrl->SetValue(wxEmptyString);
        m_replacementWordCtrl->SetValue(wxEmptyString);
    }
    else
    {
        m_customWordCtrl->SetValue(m_transformer->GetStrings()[i]);
        m_replacementWordCtrl->SetValue(m_transformer->GetReplacements()[i]);

        m_replacementWordCtrl->SetFocus();
    }

    m_ignoreEvents = false;
}


/*
 * wxEVT_COMMAND_LISTBOX_SELECTED event handler for ID_CUSTOM_WORD_LISTBOX
 */

void wxTTSCustomPronunciationDialog::OnCustomWordListboxSelected( wxCommandEvent& event )
{
    if (m_ignoreEvents)
        return;
        
    ShowWord(event.GetSelection());
}


/*
 * wxEVT_COMMAND_TEXT_UPDATED event handler for ID_CUSTOM_REPLACEMENT
 */

void wxTTSCustomPronunciationDialog::OnCustomReplacementTextUpdated( wxCommandEvent& WXUNUSED(event) )
{
    if (m_ignoreEvents)
        return;

    int sel = m_wordListCtrl->GetSelection();
    if (sel != -1)
    {
        m_transformer->GetReplacements()[sel] = m_replacementWordCtrl->GetValue();
        m_transformer->SetDirty(true);
    }
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BUTTON
 */

void wxTTSCustomPronunciationDialog::OnAddCustomWordClick( wxCommandEvent& WXUNUSED(event) )
{
    wxString word = wxGetTextFromUser(_("Enter a word"), _("New Word"), wxEmptyString, this).Lower();
    if (word.IsEmpty())
        return;
        
    if (m_transformer->HasString(word))
    {
        wxMessageBox(_("Sorry, this word has already been aded."), _("New Word"), wxICON_INFORMATION|wxOK, this);
        return;
    }

    m_ignoreEvents = true;

    int insertBefore = -1;

    size_t i;
    for (i = 0; i < m_transformer->GetStrings().GetCount(); i++)
    {
        wxString s(m_transformer->GetStrings()[i]);
        if (word < s)
        {
            insertBefore = i;
            break;
        }
    }

    int newPosition;
    if (insertBefore == -1)
    {
        m_wordListCtrl->Append(word);
        m_transformer->AddString(word, wxEmptyString);
        newPosition = m_transformer->GetStrings().GetCount()-1;
    }
    else
    {
        m_wordListCtrl->Insert(word, insertBefore);
        m_transformer->InsertString(word, wxEmptyString, insertBefore);
        newPosition = insertBefore;
    }

    m_wordListCtrl->SetSelection(newPosition);

    m_ignoreEvents = false;
    
    ShowWord(newPosition);
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_REMOVE_CUSTOM_WORD
 */

void wxTTSCustomPronunciationDialog::OnRemoveCustomWordClick( wxCommandEvent& WXUNUSED(event) )
{
    int sel = m_wordListCtrl->GetSelection();
    if (sel != -1)
    {
        ShowWord(-1);
        
        m_ignoreEvents = true;
        
        m_wordListCtrl->Delete(sel);
        m_transformer->RemoveString(sel);
        
        if (m_wordListCtrl->GetCount() > 0)
        {
            m_wordListCtrl->SetSelection(0);
            ShowWord(0);
        }

        m_ignoreEvents = false;
    }
}


/*
 * wxEVT_UPDATE_UI event handler for ID_REMOVE_CUSTOM_WORD
 */

void wxTTSCustomPronunciationDialog::OnRemoveCustomWordUpdate( wxUpdateUIEvent& event )
{
    event.Enable(m_wordListCtrl->GetSelection() != -1);
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_CUSTOM_WORD_SAY
 */

void wxTTSCustomPronunciationDialog::OnCustomWordSayClick( wxCommandEvent& WXUNUSED(event) )
{
    wxString word = m_customWordCtrl->GetValue();
    if (!word.IsEmpty() && m_speech)
    {
        m_speech->SetProperty(wxTTS_PROP_NO_SUBSTITUTIONS, true);
        m_speech->Speak(word);
        m_speech->SetProperty(wxTTS_PROP_NO_SUBSTITUTIONS, false);
    }
}


/*
 * wxEVT_UPDATE_UI event handler for ID_CUSTOM_WORD_SAY
 */

void wxTTSCustomPronunciationDialog::OnCustomWordSayUpdate( wxUpdateUIEvent& event )
{
    event.Enable(m_wordListCtrl->GetSelection() != -1);
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_CUSTOM_REPLACEMENT_SAY
 */

void wxTTSCustomPronunciationDialog::OnCustomReplacementSayClick( wxCommandEvent& WXUNUSED(event) )
{
    wxString word = m_replacementWordCtrl->GetValue();
    if (!word.IsEmpty() && m_speech)
    {
        m_speech->SetProperty(wxTTS_PROP_NO_SUBSTITUTIONS, true);
        m_speech->Speak(word);
        m_speech->SetProperty(wxTTS_PROP_NO_SUBSTITUTIONS, false);
    }
}


/*
 * wxEVT_UPDATE_UI event handler for ID_CUSTOM_REPLACEMENT_SAY
 */

void wxTTSCustomPronunciationDialog::OnCustomReplacementSayUpdate( wxUpdateUIEvent& event )
{
    event.Enable(m_wordListCtrl->GetSelection() != -1);
}


/*
 * wxEVT_UPDATE_UI event handler for ID_CUSTOM_WORD
 */

void wxTTSCustomPronunciationDialog::OnCustomWordUpdate( wxUpdateUIEvent& event )
{
    event.Enable(m_wordListCtrl->GetSelection() != -1);
}


/*
 * wxEVT_UPDATE_UI event handler for ID_CUSTOM_REPLACEMENT
 */

void wxTTSCustomPronunciationDialog::OnCustomReplacementUpdate( wxUpdateUIEvent& event )
{
    event.Enable(m_wordListCtrl->GetSelection() != -1);
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_HELP
 */
#if 0
void wxTTSCustomPronunciationDialog::OnHelpClick( wxCommandEvent& WXUNUSED(event) )
{
    //wxGetApp().ShowHelp(ID_CUSTOM_PRONUNCIATION_DIALOG, this);
}
#endif

// An HTML window

wxTTSHtmlWindow::wxTTSHtmlWindow(wxWindow* parent, wxWindowID id,
        const wxPoint& pos, const wxSize& size, long style):
      wxHtmlWindow(parent, id, pos, size, style)
{
    SetBorders(10);

#if wxCHECK_VERSION(2,5,3) && defined(__WXGTK20__)
    int fontSize = 11;

    SetStandardFonts(fontSize);
#endif
}

bool wxTTSHtmlWindow::ScrollToAnchor(const wxString& anchor)
{
    wxLogNull logNull;

    bool success = wxHtmlWindow::ScrollToAnchor(anchor);
    if (success)
    {
        // Scroll to 1 unit before, since it seems to be 1 out
        int viewX, viewY;
        GetViewStart(& viewX, & viewY);
        if (viewY > 0)
        {
            Scroll(viewX, viewY-1);
        }
    }
    return success;
}

void wxTTSHtmlWindow::ShowDisabled()
{
    wxColour backgroundColourRGB = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) ;
    wxString colourStr(backgroundColourRGB.GetAsString(wxC2S_HTML_SYNTAX));

    wxString htmlStr;
    htmlStr << wxT("<HTML><HEAD></HEAD><BODY BGCOLOR=\"") << colourStr << wxT("\">");
    htmlStr << wxT("</BODY></HTML>");
    SetPage(htmlStr);
}

void wxTTSHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& info)
{
    wxString url = info.GetHref();
    wxStringTokenizer tok(url, wxT(":"));
    if (tok.HasMoreTokens())
    {
        wxString tok1 = tok.GetNextToken();
        wxString tok2 = tok.GetNextToken();
        if (tok1 == wxT("http") || tok1 == wxT("externalhttp"))
        {
            wxString url(wxT("http:") + tok2);
            wxLaunchDefaultBrowser(url);
        }
        else
        {
            wxHtmlWindow::OnLinkClicked(info);
        }
    }
}
